﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using MapEditor;
using Microsoft.Xna.Framework.Net;

namespace PFAGame
{
    public abstract class AObject
    {
        protected Vector2 position = new Vector2(0,0);
        protected Vector2 orientation = new Vector2(0, 1);
        protected Rectangle displayRectangle = new Rectangle();
        protected Vector2 direction = new Vector2(0, 0);
        protected float radius = 0.5f;

        internal enum e_object {
            ARMOR, BERSERKER, HEAL,
            PROJECTILEMOB, PROJECTILESPEC, PROJECTILEQUEEN, PROJECTILETOWER
        };

        internal e_object obj;

        public Vector2 Position { get { return position; } set { position = value; } }
        public Vector2 Orientation { get { return orientation; } set { orientation = value; } }
        public Vector2 Direction { get { return direction; } set { direction = value; } }
        public float Radius { get { return radius; } set { radius = value; } }
        
        static int staticId = 0;

        public int Id
        {
            get;
            set;
        }

        public virtual void init()
        {
            Id = staticId++;
        }

        public virtual void update(GameTime gameTime)
        {
        }

        public virtual void draw(GameTime gameTime, Camera camera)
        {
            // calcule la position d'affichage
            //TODO: trouver pourquoi le placement des objets dépend de la résolution
            displayRectangle = new Rectangle((int)((position.X * camera.ZoomLevel) - (camera.Position.X * camera.ZoomLevel) + camera.OffsetMiddleScreen.X - camera.ZoomLevel + 0.5 * camera.ZoomLevel),
                                             (int)((position.Y * camera.ZoomLevel) - (camera.Position.Y * camera.ZoomLevel) + camera.OffsetMiddleScreen.Y - camera.ZoomLevel - 0.2 * camera.ZoomLevel),
                                          camera.ZoomLevel,
                                          camera.ZoomLevel);
        }

        public float getSquaredDistance(Vector2 otherPosition)
        {
            return (otherPosition - position).LengthSquared();
        }

        #region static

        /// <summary>
        /// retourne la liste des éléments touché par le raycast.
        /// </summary>
        /// <param name="position"> origine du raycast</param>
        /// <param name="direction"> direction du raycast</param>
        /// <param name="distance"> longueur du cone</param>
        /// <param name="angleMax"> angle du cone</param>
        /// <param name="list">list testé</param>
        /// <returns></returns>
        static public List<AObject> coneCast(Vector2 position, Vector2 direction, float distance, float angleMax, List<AMob> list)
        {
            List<AObject> output = new List<AObject>();
            foreach (AObject obj in list)
            {
                Vector2 vecteur = position - obj.Position;

                // test distance
                if (vecteur.LengthSquared() > (distance + obj.radius) * (distance + obj.radius))
                    continue;

                // test angle
                vecteur.Normalize();
                float angle = (float)(Math.Acos(vecteur.X * direction.X + vecteur.Y * direction.Y) * 180 / Math.PI);
                if (angle > angleMax / 2)
                    continue;
                output.Add(obj);
            }
            return output;
        }

        /// <summary>
        /// retourne la liste des éléments touché par le raycast.
        /// </summary>
        /// <param name="position"> origine du raycast</param>
        /// <param name="distance"> rayon de la sphére</param>
        /// <param name="list">list testé</param>
        /// <returns></returns>
        static public List<AObject> SphereCast(Vector2 position, float distance, List<AMob> list)
        {
            List<AObject> output = new List<AObject>();
            foreach (AObject obj in list)
            {
                Vector2 vecteur = position - obj.Position;

                // test distance
                if (vecteur.LengthSquared() > (distance + obj.radius) * (distance + obj.radius))
                    continue;

                output.Add(obj);
            }
            return output;
        }

        /// <summary>
        /// retourne la liste des éléments touché par le raycast.
        /// </summary>
        /// <param name="position"> origine du raycast</param>
        /// <param name="distance"> rayon de la sphére</param>
        /// <param name="list">list testé</param>
        /// <returns></returns>
        static public List<AObject> SphereCast(Vector2 position, float distance, List<APlayer> list)
        {
            List<AObject> output = new List<AObject>();
            foreach (AObject obj in list)
            {
                Vector2 vecteur = position - obj.Position;

                // test distance
                if (vecteur.LengthSquared() > (distance + obj.radius) * (distance + obj.radius))
                    continue;

                output.Add(obj);
            }
            return output;
        }

        static public bool SphereCastBool(Vector2 position, float distance, List<AMob> list)
        {
            foreach (AObject obj in list)
            {
                Vector2 vecteur = position - obj.Position;
                // test distance
                if (vecteur.LengthSquared() <= (distance + obj.radius) * (distance + obj.radius))
                    return true; 
            }
            return false;
        }

        #endregion
    }
}
